package ua.lviv.franko.solvers.stressanalysis.oneDimention.cylindrical;

import java.util.ArrayList;
import java.util.List;

import ua.lviv.franko.integration.IFunction1D;
import ua.lviv.franko.integration.VectorFunction1D;
import ua.lviv.franko.integration.VectorFunctionWithoutDerivatives1D;

public class FEElementLinear extends AbstractElement1D {

	public FEElementLinear(EquationParameters eParams, int elNumber, final double left, final double right) {
		super(eParams, elNumber, left, right);
		final double h = right - left;
		baseFunctions = new ArrayList<IFunction1D>();
		baseFunctions.add(new IFunction1D() {

			@Override
			public double calculate(double x) {
				if ((x < left) || (x > right)) {
					return 0.0;
				}
				return (right - x) / h;
			}

			@Override
			public double calculateDerivaty(double x) {
				if ((x < left) || (x > right)) {
					return 0.0;
				}
				return -1.0 / h;
			}
		});

		baseFunctions.add(new IFunction1D() {

			@Override
			public double calculate(double x) {
				if ((x < left) || (x > right)) {
					return 0.0;
				}
				return ((x - left) / h);
			}

			@Override
			public double calculateDerivaty(double x) {
				if ((x < left) || (x > right)) {
					return 0.0;
				}
				return 1.0 / h;
			}
		});
	}

	@Override
	public double[] calculate(double x, double[] results) {
		double v1 = baseFunctions.get(0).calculate(x);
		double v2 = baseFunctions.get(1).calculate(x);
		return new double[] { v1 * results[NUMBER_OF_UNKNOWNS * elNumber] + v2 * results[NUMBER_OF_UNKNOWNS * (elNumber + 1)],
				v1 * results[NUMBER_OF_UNKNOWNS * elNumber + 1] + v2 * results[NUMBER_OF_UNKNOWNS * (elNumber + 1) + 1] };
	}

	@Override
	public double[] calculateDerivaty(double x, double[] results) {
		double v1 = baseFunctions.get(0).calculateDerivaty(x);
		double v2 = baseFunctions.get(1).calculateDerivaty(x);
		return new double[] { v1 * results[NUMBER_OF_UNKNOWNS * elNumber] + v2 * results[NUMBER_OF_UNKNOWNS * (elNumber + 1)],
				v1 * results[NUMBER_OF_UNKNOWNS * elNumber + 1] + v2 * results[NUMBER_OF_UNKNOWNS * (elNumber + 1) + 1] };
	}

	@Override
	protected ElementMatrix calculateSmallData(int i, int j) {
		ElementMatrix res = new ElementMatrix(this.getNodesNumbers());

		final IFunction1D fi = baseFunctions.get(i);
		final IFunction1D fj = baseFunctions.get(j);

		double[] tmp = gau.integrate(left, right, new VectorFunction1D() {

			@Override
			public double[] calculate(double x) {
				double fiDer = fi.calculateDerivaty(x);
				double fjDer = fj.calculateDerivaty(x);
				double fiVal = fi.calculate(x);
				double fjVal = fj.calculate(x);
				double g = eParams.getG();
				double d = eParams.getD();
				return new double[] {
						// first row
						fiDer * fjDer * g, -g * fjDer * fiVal,
						// second row
						g * fjDer * fiVal, d * fiDer * fjDer + g * fjVal };
			}

			@Override
			public double[] calculateDerivaty(double x) {

				return null;
			}

			@Override
			public int vectorSize() {
				return 4;
			}
		});

		// for (int k = 0; k < tmp.length; k++) {
		// System.err.print(tmp[k] + "\t");
		// }
		// System.err.println();
		for (int k = 0; k < NUMBER_OF_UNKNOWNS; k++) {
			res.matrix[k][0] = tmp[NUMBER_OF_UNKNOWNS * k];
			res.matrix[k][1] = tmp[NUMBER_OF_UNKNOWNS * k + 1];
		}
		// right hand side
		res.vector = gau.integrate(left, right, new VectorFunctionWithoutDerivatives1D(2) {

			@Override
			public double[] calculate(double x) {
				double fiVal = fi.calculate(x);

				return new double[] { fiVal * eParams.getF1().calculate(x), fiVal * eParams.getF2().calculate(x) };
			}
		});

		return res;
	}

	@Override
	public List<Integer> getNodesNumbers() {
		List<Integer> result = new ArrayList<Integer>();
		result.add(elNumber);
		result.add(elNumber + 1);
		return result;
	}

	@Override
	protected double[] calculateSmallUpdatedVector(int i, final EquationParameters parameters) {
		final IFunction1D fi = baseFunctions.get(i);
		return gau.integrate(left, right, new VectorFunctionWithoutDerivatives1D(2) {

			@Override
			public double[] calculate(double x) {
				double fiVal = fi.calculate(x);

				return new double[] { fiVal * eParams.getF1().calculate(x), fiVal * eParams.getF2().calculate(x) };
			}
		});
	}

}
